﻿using AutoMapper;
using MediatR;
using WeatherHistory.Data.Entities;
using WeatherHistory.Data.Repositories.Interfaces;
using WeatherHistory.Shared.Exceptions;

namespace WeatherHistory.Api.CommandsQueries.Commands.Regions.Create;

public class CreateRegionsCommandHandler : IRequestHandler<CreateRegionsCommandRequest, CreateRegionsCommandResponse>
{
    private readonly IMapper _mapper;
    private readonly IRegionRepository _regionRepository;
    private readonly IRegionTypeRepository _regionTypeRepository;

    public CreateRegionsCommandHandler(IRegionRepository regionRepository, IMapper mapper, IRegionTypeRepository regionTypeRepository)
    {
        _regionRepository = regionRepository;
        _mapper = mapper;
        _regionTypeRepository = regionTypeRepository;
    }

    public async Task<CreateRegionsCommandResponse> Handle(CreateRegionsCommandRequest request, CancellationToken cancellationToken)
    {
        const double coordinatesComparisonTolerance = 0.000001;
        var regionExists = await _regionRepository.AnyAsync(x => Math.Abs(x.Latitude - request.Latitude) < coordinatesComparisonTolerance
                                                                 && Math.Abs(x.Longitude - request.Longitude) < coordinatesComparisonTolerance, cancellationToken);
        if (regionExists) throw new ConflictException("Регион с такими координатами уже существует");


        var newRegion = new Region();
        newRegion.Latitude = request.Latitude;
        newRegion.Longitude = request.Longitude;
        newRegion.Name = request.Name;
        newRegion.CreatedById = request.CreatorId;

        if (request.RegionType != null)
        {
            var regionTypeExists = await _regionTypeRepository.AnyAsync(x => x.Id == request.RegionType, cancellationToken);
            if (regionTypeExists == false) throw new ConflictException($"Тип региона с id '{request.RegionType}' не найден");
            newRegion.RegionTypeId = request.RegionType;
        }

        if (request.ParentRegion != null)
        {
            var parentRegion = await _regionRepository.FirstOrDefaultAsync(x => x.Name == request.ParentRegion, cancellationToken);
            newRegion.ParentRegionId = parentRegion?.Id;
            newRegion.ParentRegion = parentRegion;
        }

        await _regionRepository.InsertAsync(newRegion, cancellationToken);
        return _mapper.Map<CreateRegionsCommandResponse>(newRegion);
    }
}